
package org.yuanqiframework.yuanqi.boot.log.aspect;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.yuanqiframework.yuanqi.boot.sys.entity.SysOperLog;
import org.yuanqiframework.yuanqi.boot.sys.service.SysOperLogService;
import org.yuanqiframework.yuanqi.core.utils.AddressUtils;
import org.yuanqiframework.yuanqi.web.auth.AuthContext;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 操作日志记录处理
 */
@Aspect
@Component
public class OperLogAspect {
    private static final Logger log = LoggerFactory.getLogger(OperLogAspect.class);

    @Resource
    private SysOperLogService sysOperLogService;

    /**
     * 设置controller层切入点
     */
    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void controllerPointcut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "controllerPointcut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "controllerPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    @Async
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            // 获取当前的用户
            String username = AuthContext.getUserId();
            if (username == null) {
                username = "未登录用户";
            }
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // *========数据库日志=========*//
            SysOperLog operLog = new SysOperLog();
            operLog.setStatus("0"); // 操作状态（0正常 1异常）
            operLog.setOperName(username); // 操作人员
            operLog.setOperIp(request.getRemoteAddr()); // 主机地址
            operLog.setOperUrl(request.getRequestURI()); // 请求URL
            operLog.setOperMethod(request.getMethod()); // 请求方式
            operLog.setOperLocation(AddressUtils.getRealAddressByIP(request.getRemoteAddr()));
            operLog.setOperModule(joinPoint.getTarget().getClass().getSimpleName()); // 操作模块
            operLog.setOperType(getOperType(request.getMethod())); // 操作类型

            // 请求的参数
            Object[] args = joinPoint.getArgs();
            try {
                String params = "";
                if ("GET".equals(request.getMethod())) {
                    // 对于GET请求，记录查询参数
                    params = request.getQueryString() != null ? request.getQueryString() : "";
                    //解码
                    params = java.net.URLDecoder.decode(params, "UTF-8");
                } else {
                    // 对于其他请求，使用原来的处理方式
                    params = JSON.toJSONString(args);
                }
                operLog.setOperParam(params); // 请求参数
            } catch (Exception exp) {
                log.error("获取参数失败", exp);
            }

            // 请求的结果
            operLog.setOperTime(new Date()); // 操作时间

            if (e != null) {
                operLog.setStatus("1"); // 操作状态（0正常 1异常）
                operLog.setErrorMsg(e.getMessage()); // 错误消息
            }

            // 保存数据库
            sysOperLogService.save(operLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 根据请求方式获取操作类型
     *
     * @param method 请求方式
     * @return 操作类型
     */
    private String getOperType(String method) {
        switch (method) {
            case "GET":
                return "4"; // 查询
            case "POST":
                return "5"; // 新增
            case "PUT":
                return "5"; // 修改
            case "DELETE":
                return "5"; // 删除
            default:
                return "5"; // 其他
        }
    }
}